package com.duojuhe.coremodule.quartz.util;

import com.duojuhe.coremodule.quartz.enums.QuartzEnum;
import com.duojuhe.common.enums.SystemEnum;
import com.duojuhe.common.exception.DuoJuHeSystemException;
import com.duojuhe.common.utils.idgenerator.UUIDUtils;
import com.duojuhe.common.utils.thread.ThreadUtils;
import com.duojuhe.coremodule.quartz.entity.QuartzJob;
import com.duojuhe.coremodule.quartz.entity.QuartzJobLog;
import com.duojuhe.coremodule.quartz.mapper.QuartzJobLogMapper;
import com.duojuhe.coremodule.quartz.mapper.QuartzJobMapper;
import com.duojuhe.coremodule.quartz.util.bean.JobTask;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang3.StringUtils;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import javax.annotation.Resource;
import org.springframework.stereotype.Component;


import javax.annotation.Resource;
import java.util.Date;

/**
 * 抽象quartz调用
 *
 */
@Slf4j
@Component
public abstract class AbstractQuartzJob implements Job {
    @Resource
    private QuartzJobLogMapper quartzJobLogMapper;
    @Resource
    private QuartzJobMapper quartzJobMapper;
    /**
     * 线程本地变量
     */
    private static ThreadLocal<Date> threadLocal = new ThreadLocal<>();

    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        JobTask jobTask = new JobTask();
        try{
            BeanUtils.copyProperties(jobTask,context.getMergedJobDataMap().get(ScheduleUtils.jobBeanKey));
            before(context, jobTask);
            doExecute(context, jobTask);
            after(context, jobTask, null);
        }catch (Exception e){
            log.error("任务执行异常  - ：", e);
            after(context, jobTask, e);
        }
    }

    /**
     * 执行前
     *
     * @param context 工作执行上下文对象
     * @param jobTask 系统计划任务
     */
    protected void before(JobExecutionContext context, JobTask jobTask) {
        threadLocal.set(new Date());
    }

    /**
     * 执行后
     *
     * @param context 工作执行上下文对象
     * @param jobTask 系统计划任务
     */
    protected void after(JobExecutionContext context, JobTask jobTask, Exception e) {
        try {
            if (jobTask==null|| StringUtils.isBlank(jobTask.getJobId())){
                return;
            }
            if (e instanceof DuoJuHeSystemException){
                return;
            }
            //开始时间
            Date startTime = threadLocal.get();
            //结束时间
            Date nowDate = new Date();
            final QuartzJobLog jobLog = new QuartzJobLog();
            jobLog.setLogId(UUIDUtils.getUUID32());
            jobLog.setJobId(jobTask.getJobId());
            jobLog.setSpringId(jobTask.getSpringId());
            jobLog.setGroupId(jobTask.getGroupId());
            jobLog.setJobName(jobTask.getJobName());
            jobLog.setCronExpression(jobTask.getCronExpression());
            jobLog.setIsSyncCode(jobTask.getIsSyncCode());
            jobLog.setClassPath(jobTask.getClassPath());
            jobLog.setMethodName(jobTask.getMethodName());
            jobLog.setCreateTime(nowDate);
            jobLog.setStartTime(startTime);
            jobLog.setStopTime(nowDate);
            jobLog.setOperationStatusCode(SystemEnum.OPERATION_STATUS.SUCCESS.getKey());
            long runMs = nowDate.getTime() - startTime.getTime();
            jobLog.setRemark(jobTask.getJobName() + " 总共耗时：" + runMs + "毫秒");
            String runStr = QuartzEnum.QUARTZ_STATUS.RUNNING.getValue();
            if (e != null){
                jobLog.setOperationStatusCode(SystemEnum.OPERATION_STATUS.FAILED.getKey());
                String errorMsg = e.getMessage();
                jobLog.setDescription(errorMsg);
                runStr = QuartzEnum.QUARTZ_STATUS.RUN_EXCEPTION.getValue();
            }
            QuartzJob jobNew = new QuartzJob();
            jobNew.setJobId(jobTask.getJobId());
            jobNew.setLastTime(context.getFireTime());
            jobNew.setNextTime(context.getNextFireTime());
            jobNew.setRemark(runStr);
            quartzJobMapper.updateByPrimaryKeySelective(jobNew);
            // 添加到队列中
            log.info("【调度任务执行日志】{}" ,jobLog.toString());
            // 异步添加到数据库
            if (e != null){
                //目前只记录出现异常的执行日志 2022-09-02
                ThreadUtils.execute(() -> quartzJobLogMapper.insertSelective(jobLog));
            }
        }catch (Exception exc){
            log.error("调度任务执行后方法 出现异常" ,exc);
        }finally {
            threadLocal.remove();
        }
    }

    /**
     * 执行方法，由子类重载
     *
     * @param context 工作执行上下文对象
     * @param jobTask 系统计划任务
     * @throws Exception 执行过程中的异常
     */
    protected abstract void doExecute(JobExecutionContext context, JobTask jobTask) throws Exception;
}
